package com.mmall.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.type.JavaType;
import org.codehaus.jackson.type.TypeReference;

import java.io.IOException;
import java.text.SimpleDateFormat;

@Slf4j
public class JsonUtil {

    private static ObjectMapper objectMapper = new ObjectMapper();
    static {
        // 对象的所有字段全部列入 (包括为null的)
        objectMapper.setSerializationInclusion(JsonSerialize.Inclusion.ALWAYS);

        // 取消默认转换timestamps形式 TODO
        objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);

        // 忽略空bean转json的错误
        objectMapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);

        // 所有日期格式同一处理为：yyyy-MM-dd HH:mm:ss
        objectMapper.setDateFormat(new SimpleDateFormat(DateTimeUtil.STANDARD_FORMAT));

        // 忽略在json字符串中存在，但是在java对象中不存在对应属性的情况，防止错误 （确保高可用）
        objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    /**
     * obj --> String
     * @param obj
     * @param <T>
     * @return
     */
    // TODO ? T 与 ？的区别
    public static <T> String obj2String(T obj){
        if (obj == null){
            return null;
        }
        try {
            return obj instanceof String ? (String)obj :objectMapper.writeValueAsString(obj);
        }catch (Exception e){
            log.warn("Parse object to String error",e);
            return null;
        }
    }

    /**
     * obj --> String (带格式化的)
     * @param obj
     * @param <T>
     * @return
     */
    public static <T> String obj2StringPretty(T obj){
        if (obj == null){
            return null;
        }
        try {
            return obj instanceof String ? (String)obj :objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        }catch (Exception e){
            log.warn("Parse object to String error",e);
            return null;
        }
    }

    /**
     * String --> obj （单个对象适用）
     * @param str
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T string2Obj(String str, Class<T> clazz){
        if (StringUtils.isEmpty(str) || clazz == null){
            return null;
        }
        try {
            return clazz.equals(String.class)? (T)str: objectMapper.readValue(str, clazz);
        } catch (Exception e) {
            log.warn("Parse String to obj error",e);
            return null;
        }
    }

    /**
     * String --> obj (集合对象适用)
     * @param str
     * @param collectionClass
     * @param elementsClasses
     * @param <T>
     * @return
     */
    public static <T> T string2Obj(String str, Class<?> collectionClass, Class<?> ...elementsClasses){
        // TODO ?
        JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClass, elementsClasses);
        try {
            return  objectMapper.readValue(str, javaType);
        } catch (IOException e) {
            log.warn("Parse String to obj error",e);
            return null;
        }
    }

    /**
     * String --> obj 通用反序列化方法
     * @param str
     * @param typeReference
     * @param <T>
     * @return
     */
    public static <T> T string2Obj(String str, TypeReference<T> typeReference){
        if (StringUtils.isEmpty(str) || typeReference == null){
            return null;
        }
        try {
            return (T)(typeReference.getType().equals(str)? str : objectMapper.readValue(str, typeReference));
        } catch (IOException e) {
            log.warn("Parse String to obj error",e);
            return null;
        }
    }

    /*public static void main(String[] args) {
        User u1 = new User();
        u1.setUsername("Tom");
        u1.setPhone("11111111111111111");

        User u2 = new User();
        u2.setUsername("Tom00002");
        u2.setPhone("22222222222222222");

        String strU1Json = JsonUtil.obj2String(u1);
        String strU1JsonPretty = JsonUtil.obj2StringPretty(u1);

        log.info("userJson: {}",strU1Json);
        log.info("userJsonPretty: {}",strU1JsonPretty);

        System.out.println("=================================================");
        User user = JsonUtil.string2Obj(strU1Json, User.class);

        List<User>  lstUser =  Lists.newArrayList();
        lstUser.add(u1);
        lstUser.add(u2);
        String strUsrList = JsonUtil.obj2StringPretty(lstUser);
        log.info("strUsrList: {}",strUsrList);
        System.out.println("=================================================");

        //List<User>  lstUserDe = JsonUtil.string2Obj(strUsrList, List.class);
        List<User>  lstUserDe = JsonUtil.string2Obj(strUsrList, new TypeReference<List<User>>() {});

        System.out.println("=================================================");
        List<User>  lstUserDe2 = JsonUtil.string2Obj(strUsrList, List.class, User.class);

    }*/





}
